package widget.badge;

import android.support.annotation.NonNull;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

public class BadgeNode {

    private final String name;
    private final WeakReference<BadgeNode> parent;
    private final WeakReference<IBadge> listener;
    private final Map<String, WeakReference<BadgeNode>> tree
            = Collections.synchronizedMap(new LinkedHashMap<String, WeakReference<BadgeNode>>());

    public BadgeNode(String name, IBadge iBadge, BadgeNode parent) {
        this.name = name;
        this.listener = new WeakReference<>(iBadge);
        this.parent = new WeakReference<>(parent);
    }

    public String getName() {
        return name;
    }

    public BadgeNode getParent() {
        return parent != null ? parent.get() : null;
    }

    public Map<String, WeakReference<BadgeNode>> tree() {
        return tree;
    }

    public void addNode(BadgeNode node) {
        tree.put(node.getName(), new WeakReference<>(node));
    }

    private void callback(int index, int count) {
        IBadge iBadge = listener != null ? listener.get() : null;
        if (iBadge != null)
            iBadge.onBadgeChanged(index, count);
    }

    public void notifyChange(int count) {
        BadgeNode node = parent != null ? parent.get() : null;
        if (node != null) {
            int index = indexInParent();
            if (index >= 0) {
                node.callback(index, count);
                node.notifyChange(count);
            }
        }
    }

    public int indexInParent() {
        BadgeNode node = parent != null ? parent.get() : null;
        if (node != null && !node.tree().isEmpty()) {
            int i = 0;
            for (Map.Entry<String, WeakReference<BadgeNode>> entry : node.tree().entrySet()) {
                String key = entry.getKey();
                if (key != null && key.equals(this.name)) {
                    return i;
                }
                i++;
            }
        }
        return -1;
    }

    public BadgeNode getNode(String name) {
        if (tree.isEmpty())
            return null;
        if (tree.containsKey(name)) {
            WeakReference<BadgeNode> reference = tree.get(name);
            BadgeNode child = reference != null ? reference.get() : null;
            if (child != null && child.getName().equals(name))
                return child;
        }
        return null;
    }

    public BadgeNode findNode(String name) {
        return findNode(name, this);
    }

    private BadgeNode findNode(String name, @NonNull BadgeNode parent) {
        if (parent.getName().equals(name)) {
            return parent;
        }
        if (parent.tree().isEmpty())
            return null;
        BadgeNode target = parent.getNode(name);
        if (target != null)
            return target;
        for (Map.Entry<String, WeakReference<BadgeNode>> entry : parent.tree().entrySet()) {
            WeakReference<BadgeNode> reference = entry.getValue();
            BadgeNode child = reference != null ? reference.get() : null;
            target = child != null ? findNode(name, child) : null;
            if (target != null)
                return target;
        }
        return null;
    }

}
